export default function init(canvas) {
  var center_x = canvas.width / 2;
  var stretch_factor = 600 / canvas.height;
  var y_speed = 3 / stretch_factor;
  var ctx = canvas.getContext('2d');
  ctx.globalCompositeOperation = 'lighter';
  // tree
  var t = new Tree();
  t.init(ctx);
  for (var i = 0; i < 3; i++) {
    new Branch(
      new Vector(center_x, canvas.height),
      new Vector(Math.random(-1, 1), -y_speed),
      15 / stretch_factor,
      canvas.width,
      Branch.randomrgba(0, 255, 0.3),
      t
    );
  }
  t.render();
}

var Vector = function(x, y) {
  this.x = x || 0;
  this.y = y || 0;
};
Vector.prototype = {
  add: function(v) {
    this.x += v.x;
    this.y += v.y;
    return this;
  },
  length: function() {
    return Math.sqrt(this.x * this.x + this.y * this.y);
  },
  rotate: function(theta) {
    this.x = Math.cos(theta) * this.x - Math.sin(theta) * this.y;
    this.y = Math.sin(theta) * this.x + Math.cos(theta) * this.y;
    //this.x = Math.cos(theta) * x - Math.sin(theta) * y;
    //this.y = Math.sin(theta) * x + Math.cos(theta) * y;
    return this;
  },
  mult: function(f) {
    this.x *= f;
    this.y *= f;
    return this;
  }
};
var Leaf = function(p, r, c, ctx) {
  this.p = p || null;
  this.r = r || 0;
  this.c = c || 'rgba(255,255,255,1.0)';
  this.ctx = ctx;
};
Leaf.prototype = {
  render: function() {
    var that = this;
    var ctx = this.ctx;
    var f = Branch.random(1, 2);
    for (var i = 0; i < 5; i++) {
      (function(r) {
        setTimeout(function() {
          ctx.beginPath();
          ctx.fillStyle = that.color;
          ctx.moveTo(that.p.x, that.p.y);
          ctx.arc(that.p.x, that.p.y, r, 0, Branch.circle, true);
          ctx.fill();
        }, r * 60);
      })(i);
    }
  }
};
var Branch = function(p, v, r, w, c, t) {
  this.p = p || null;
  this.v = v || null;
  this.r = r || 0;
  this.w = w;
  this.length = 0;
  this.generation = 1;
  this.tree = t || null;
  this.color = c || 'rgba(255,255,255,1.0)';
  this.register();
};
Branch.prototype = {
  register: function() {
    this.tree.addBranch(this);
  },
  draw: function() {
    var ctx = this.tree.ctx;
    ctx.beginPath();
    ctx.fillStyle = this.color;
    ctx.moveTo(this.p.x, this.p.y);
    ctx.arc(this.p.x, this.p.y, this.r, 0, Branch.circle, true);
    ctx.fill();
  },
  modify: function() {
    var angle = 0.18 - 0.1 / this.generation;
    this.p.add(this.v);
    this.length += this.v.length();
    this.r *= 0.99;
    this.v.rotate(Branch.random(-angle, angle)); //.mult(0.996);
    if (this.r < this.w / 1900 || this.generation > 10) {
      this.tree.removeBranch(this);
      var l = new Leaf(this.p, 10, this.color, this.tree.ctx);
      l.render();
    }
  },
  grow: function() {
    this.draw();
    this.modify();
    this.fork();
  },
  fork: function() {
    var p = this.length - Branch.random(this.w / 20, this.w / 10); // + (this.generation * 10);
    if (p > 0) {
      var n = Math.round(Branch.random(1, 3));
      this.tree.stat.fork += n - 1;
      for (var i = 0; i < n; i++) {
        Branch.clone(this);
      }
      this.tree.removeBranch(this);
    }
  }
};
Branch.circle = 2 * Math.PI;
Branch.random = function(min, max) {
  return Math.random() * (max - min) + min;
};
Branch.clone = function(b) {
  var r = new Branch(
    new Vector(b.p.x, b.p.y),
    new Vector(b.v.x, b.v.y),
    b.r,
    b.w,
    b.color,
    b.tree
  );
  r.generation = b.generation + 1;
  return r;
};
Branch.rgba = function(r, g, b, a) {
  return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
};
Branch.randomrgba = function(min, max, a) {
  return Branch.rgba(
    Math.round(Branch.random(min, max)),
    Math.round(Branch.random(min, max)),
    Math.round(Branch.random(min, max)),
    a
  );
};
var Tree = function() {
  var branches = [];
  var timer;
  this.stat = {
    fork: 0,
    length: 0
  };
  this.addBranch = function(b) {
    branches.push(b);
  };
  this.removeBranch = function(b) {
    for (var i = 0; i < branches.length; i++) {
      if (branches[i] === b) {
        branches.splice(i, 1);
        return;
      }
    }
  };
  this.render = function(fn) {
    var that = this;
    timer = setInterval(function() {
      fn && fn.apply(that, arguments);
      if (branches.length > 0) {
        for (var i = 0; i < branches.length; i++) {
          branches[i].grow();
        }
      } else {
        //clearInterval(timer);
      }
    }, 1000 / 30);
  };
  this.init = function(ctx) {
    this.ctx = ctx;
  };
  this.abort = function() {
    branches = [];
    this.stat = {
      fork: 0,
      length: 0
    };
  };
};

